package fnic.prehand.augment;


import java.math.BigDecimal;
import java.util.zip.CRC32;

/**
 * IP地址转换，字符串到长整形或者长整形到字符串
 * @author sjl
 */
public class IPConverter {
	/**高位下标*/
	public static final byte HIGH = 0;
	/**低位下标*/
	public static final byte LOW = 1;
	/**  
	 * IP地址转成长整数.  
	 * @param ip  
	 * @return  result[IPConverter.HIGH],result[IPConverter.LOW]
	 */   
	public static Long[] str2long(String ip){
		Long[] result;
		if(ip.indexOf(":")>=0){
			long[] tmp = ipv62long(ip.trim());
			result = new Long[]{tmp[HIGH], tmp[LOW]};
		}else{
			result = new Long[]{null, ipv42long(ip.trim())};
		}
//		logger.debug("convert ["+ip+"] to high:"+result[0]+" low:"+result[1]);
		return result;
	}

	/**  
	 * 长整数转成IP地址.  
	 * @param high
	 * @param low
	 * @return  
	 */   
	public static String long2str(Long high, long low){
		if(high == null)
			return long2ipv4(low);
		else
			return long2ipv6(high, low);
	}
	/**  
	 * 长整数转成IP地址.  
	 * @param high
	 * @param low
	 * @return  
	 */   
	public static String decimal2str(BigDecimal high, BigDecimal low){
		if(low == null) return "";
		if(high == null)
			return long2ipv4(low.longValue());
		else
			return long2ipv6(high.longValue(), low.longValue());
	}
	/**  
	 * 长整数转成IP地址.  
	 * @param high
	 * @param low
	 * @return  
	 */   
	public static String long2str(String high, long low){
		if(high == null)
			return long2ipv4(low);
		else
			return long2ipv6(Long.parseLong(high), low);
	}
	/**  
	 * IPv6地址转成长整数.  
	 * @param ip  
	 * @return  result[IPConverter.HIGH],result[IPConverter.LOW]
	 */   
	public static long[] ipv62long(String ip) {   
		//输入的原始地址，在末尾补空格用于分割
		ip+=" ";
		String[] ipsOrg = ip.split(":");
		//补全后的地址
		String[] ips = new String[8];

		//将简写的地址补全
		for(int i=0,j=0; i<ips.length && j<ipsOrg.length; j++){
//			System.out.println("i:"+i+" j:"+j+" "+ipsOrg[j]+" "+ips.length+" "+ipsOrg.length);
			if(ipsOrg[j].trim().equals("") && (j==0 || j==ipsOrg.length-1)){
				//如果首个或末尾的地址段为空，则直接补一个0
				ips[i++] = "0";
				
			}else if(ipsOrg[j].trim().equals("") && j>0 && j<ipsOrg.length-1){
				//如果中间的地址段为空，则循环补多个0
				while(i-j<ips.length-ipsOrg.length+1){
					ips[i++] = "0";
				}
			}else{
				//如果地址段不为空，则复制
				ips[i++] = ipsOrg[j].trim();
			}
//			System.out.println("----i:"+i+" j:"+j);
		}
		//定义返回结果
		long[] num = new long[2];
		
		//转换高位
		num[HIGH] = 0x1000000000000L*Long.parseLong(ips[0], 16) + 
			0x100000000L*Long.parseLong(ips[1], 16) + 
			0x10000*Long.parseLong(ips[2], 16) + 
			Long.parseLong(ips[3], 16);
		
		//转换低位
		num[LOW] = 0x1000000000000L*Long.parseLong(ips[4], 16) + 
			0x100000000L*Long.parseLong(ips[5], 16) + 
			0x10000*Long.parseLong(ips[6], 16) + 
			Long.parseLong(ips[7], 16);
		return num;   
	} 

	/**  
	 * 长整数转成IPv6地址.  
	 * @param high
	 * @param low
	 * @return  
	 */   
	public static String long2ipv6(long high, long low) {   
		//掩码
		long mask[] = {0x000000000000FFFFL,
					0x00000000FFFF0000L,
					0x0000FFFF00000000L,
					0xFFFF000000000000L};   
		long num = 0;
		StringBuffer ipInfo = new StringBuffer();
		
		//转换低位
		for(int i=0;i<4;i++){   
			num = (low & mask[i])>>>(i*16);   
			if(i>0) ipInfo.insert(0,":");
			//若为0，则不显示
			ipInfo.insert(0,Long.toHexString(num).toUpperCase());
		}
		
		//转换高位
		for(int i=0;i<4;i++){
			num = (high & mask[i])>>>(i*16);   
			ipInfo.insert(0,":");
			//若为0，则不显示
			ipInfo.insert(0,Long.toHexString(num).toUpperCase());
		}
		//顺序反转
		String reversedIp = ipInfo.reverse().toString();
//		System.out.println("reversedIp "+reversedIp);
		//替换找到的第一个连续的0
		if(reversedIp.startsWith("0:0"))
			//位于开始
			reversedIp = reversedIp.replaceFirst("^0(:0)+", ":");
		else if(reversedIp.indexOf("0:0:")>0 && !reversedIp.endsWith("0:0"))
			//位于中间
			reversedIp = reversedIp.replaceFirst("0(:0)+:", ":");
		else
			//位于末尾
			reversedIp = reversedIp.replaceFirst("0(:0)+$", ":");
		
		//恢复顺序
		return new StringBuffer(reversedIp).reverse().toString();   
	}
	/**  
     * ip地址转成整数.  
     * @param ip  
     * @return  
     */  
	 public static long ipv42long(String ip) {
	        String[] ips = ip.split("[.]"); 
	        if(ips.length < 4){
	        	return 0;
	        }
	        long num =  16777216L*Long.parseLong(ips[0]) + 65536L*Long.parseLong(ips[1]) + 256*Long.parseLong(ips[2]) + Long.parseLong(ips[3]);   
	        return num;   
	    }   
	    /**  
	     * 整数转成ip地址.  
	     * @param ipLong  
	     * @return  
	     */  
	    public static String long2ipv4(long ipLong) {   
	        //long ipLong = 1037591503;   
	        long mask[] = {0x000000FF,0x0000FF00,0x00FF0000,0xFF000000};   
	        long num = 0;   
	        StringBuffer ipInfo = new StringBuffer();   
	        for(int i=0;i<4;i++){   
	            num = (ipLong & mask[i])>>(i*8);   
	            if(i>0) ipInfo.insert(0,".");   
	            ipInfo.insert(0,Long.toString(num,10));   
	        }   
	        return ipInfo.toString();   
	    }
	    
	    /**
	     * 将未定义IP地址转换为数据库中的用户Id
	     * @param ip
	     * @return
	     */
	    public static Long ipv42id(String ip){
	    	return ipv42id(ipv42long(ip));
	    }
	    
	    /**
	     * 将未定义IP地址转换为数据库中的用户Id
	     * @param ip
	     * @return
	     */
	    public static Long ipv42id(long ip){
			CRC32 crc32 = new CRC32();
			crc32.update(String.valueOf(ip).getBytes());
	    	return crc32.getValue() % 1073741824L + 50000000;
	    }
}